﻿using System;
using System.Runtime.Serialization;
using CI.Interfaces;

namespace CI.Organism
{
    /// <summary>The chromosome</summary>
    [DataContract]
    public class Chromosome : IChromosome
    {
        /// <summary>Chromosomes Genes Collection</summary>
        [DataMember]
        public IGeneCollection Genes { get; set; }

        /// <summary>Chromosone's GUID used to uniquely identify it in the chromosome collection</summary>
        [DataMember]
        public Guid Guid { get; set; }

        /// <summary>
        /// Take this parents Chromosome and create a new Chromosome to be put in the new Organism
        /// Mutate the current Chromosome and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new chromosome for child</returns>
        public IChromosome Mutate(double mutationRate, IOrganism childOrganism)
        {
            // create a new chromsome
            var childChromosome = new Chromosome(Guid);

            // get a new set of mutated genes for this new chromosome
            childChromosome.Genes = Genes.Mutate(mutationRate, childOrganism);

            return childChromosome;
        }

        /// <summary>
        /// do a equals comparison of one cell type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="chromosome">chromosome to compare against</param>
        /// <returns>true if equal value types</returns>
        public bool EqualsValueTypes(IChromosome chromosome)
        {
            // make sure we have a comparison
            if (chromosome == null)
                return false;

            // make sure their guids are the same
            if (Guid != chromosome.Guid)
                return false;

            // make sure they have the same gene counts
            if (Genes.Count != chromosome.Genes.Count)
                return false;

            // compare each of its genes
            foreach (IGene gene in Genes)
            {
                // find a matching gene
                IGene foundGene = chromosome.Genes.Find(gene.Guid);

                // if none found exit
                if (foundGene == null)
                    return false;

                // compare the types
                if (!gene.GetType().Equals(foundGene.GetType()))
                    return false;

                // compare its equals value
                if (!gene.EqualsValueTypes(foundGene))
                    return false;
            }

            return true;
        }

        /// <summary>
        /// create a new chromsome with the specified guid
        /// </summary>
        /// <param name="guid"></param>
        public Chromosome(Guid guid)
        {
            Guid = guid;
        }
    }
}